/*
* ========== Copyright Header Begin ==========================================
* 
* OpenSPARC T1 Processor File: cpu_lib_intf.h
* Copyright (c) 2006 Sun Microsystems, Inc.  All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
* 
* The above named program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public
* License version 2 as published by the Free Software Foundation.
* 
* The above named program is distributed in the hope that it will be 
* useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* General Public License for more details.
* 
* You should have received a copy of the GNU General Public
* License along with this work; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
* 
* ========== Copyright Header End ============================================
*/
///////////////////////////////////////////////////////////
//
// File: cpu_lib_intf.h
//


#ifndef _CPU_LIB_INTERFACE_H
#define	_CPU_LIB_INTERFACE_H

#include <stdlib.h>

// #include "vtracer.h"
//#include "prioque.h"

// This file defines interface structures for the cpu module 
// in the shared library.   

// A few instances of cpu objects could be created,
// each cpu object may have a few cpu cores, each core may
// have a few strands. 
// Cpu cores could run on separate threads of the host machine.  


// max number of Cpu's supported
const int NCPU_MAX = 64;

/////////////////////////////////////////////////////
//
// Cpu config structure
//


typedef class
{
public:
    char *name;       // cpu instance name
    char *type;       // Ultrasparc-T1, ...
    char *mmu_type;   // t1, ...

    int cpu_type;     // encoded cpu impl version
    
  
    int reg_wins;     // number of reg windows
    int tl_max;       // trap level max
    
    int itlb_size;    // number of tlb entries
    int dtlb_size;   
    
    
    int loopticks;    // number of instruction completed before incrementing stick reg
    int stickincr;    // the amount stick has to be incremented

    int cpufreq;      // cpu clock
    int stickfreq;    // system clock
    
    double cpi;          // cycles per instruction

    int delay;        // delay this number of instructions
    
    int mode;         // 1 - multithreaded (MP on MP) run; 
                      // 0 - all cpu's on a single thread;
                      
    int trace_on;     // 1 - trace enabled; 
                      // 0 - trace disabled; 

    static int execution_driven; // must be updated using the get/enable/disable functions

    static int in_execution_driven_mode();
    static void enable_execution_driven_mode();
    static void disable_execution_driven_mode();

}
VCPU_Config; 






/////////////////////////////////////////////////////
//
// Interrupt message
//
#define INTR_DATA_SIZE 8

struct VCPU_InterruptRequest
{
     int isid;		// interrupt sender ID 
     int itid;		// interrupt target ID  

     uint64_t data[INTR_DATA_SIZE];	// (sun4u only?) data
     
     uint32_t bogus_src_dev_id;	// aka INO, ie interrupt number ???

     uint32_t bogus_src_dev_type;	// bogus debug info
};






/////////////////////////////////////////////////////
//
// Cpu imported interface for the io and memory 
// subsystem 
// 
// Set of function pointers that cpu module calls 
// to send a request to the system modules.
// 
 
enum VCPU_Operation
{
    VCPU_LOAD_OP,		// Load 1,2, or more bytes from memory. Atomicity is guaranteed up to 8 bytes
    VCPU_STORE_OP,		// Store 1,2, or more bytes to memory. Atomicity is guaranteed up to 8 bytes
    VCPU_STORE_PARTIAL_OP,	// Store 1,2, or more bytes to memory, bit enabled by set bits
    VCPU_LOAD_ATOMIC_OP,	// Load atomic. Atomicity of the load is guaranteed
    VCPU_SWAP_OP,		// Swap - SunSparc 32bit swap instruction
    VCPU_CAS_OP,		// Compare And Swap - SunSparc 32bit casa, or 64bit casxa instruction
    VCPU_LDSTUB_OP,		// LoaD STore Unsigned Byte - SunSparc 8bit ldstub instruction
    VCPU_PREFETCH_OP,		// Prefetch data into the cache hierarchy
    VCPU_FLUSH_OP,		// Flush data in the cache hierarchy to memory
    VCPU_PEEK_OP,		// Read data from memory mapped registers without causing sideeffect
    VCPU_POKE_OP		// Write data to memory mapped registers without causing sideeffect
};

class SMemory;  // forward declarations
class VTracer; 
class EventQue; 

typedef struct
{
    // memory interface
    class SMemory *mem; 
                       

    // vtracer interface
    class VTracer *vtrace; 
                        
    // io interface
    int (*access_io)  
    ( 
        int vcpu_id,       // cpu id
        int operation,     // operation code
        uint64_t paddr,    // physical address
        uint32_t size,     // access size
        uint64_t &data,    // 64 bit value to read/write
        uint64_t bytemask  // access byte mask
    ); 

    // interface to access devices that mapped to asi ring
    int  (*access_asi)	
    (
        int vcpu_id,      // cpu id 
        int operation,    // operation code
        uint32_t asi,     // asi value
        uint64_t vaddr,   // virtual address
        int32_t  size,    // access size
        uint64_t &buf     // 64 bit data value
    );

    // serial device for software bring up debugging
    int (*access_serial)
    (
        uint8_t *c,      // character to read/write
        bool_t wr          // 0 - read, 1 - write
    );
}
VCPU_ImpIntf; 

 


/////////////////////////////////////////////////////
//
// Cpu module exported interface
//
// when applicable return 0- if succeed, >0- if fail.  
//
 
typedef struct
{

    // create/config method
    // return vcpu pointer
    void * (*create )        // new cpu module
    ( 
        VCPU_Config  *cinfo,   // cpu config params 
        VCPU_ImpIntf *intf     // interface to the system      
    );

    int (*reset  ) ( uint64_t pc );

    int (*destroy) ();
    
    // set/get config param
    int (*exec_cmd) 
    ( 
        char *cmd_str,   // command string
        char *reply,     // return reply string
        int reply_size   // size of reply string
    ); 

    // save restore methods
    int (*save   ) ( char *dir_name ); 
    int (*restore) ( char *dir_name );  
     
  
}
VCPU_ExInterface;


////////////////////////////////////////////////////////
//
// Get exported interface from the cpu shared library.
// 
// Assign function pointers in the interface structure. 
// 
//
// return: 0 - success; 1 - fail; 

extern "C" int get_ex_interface 
( 
    VCPU_ExInterface *intf  // pointer to the interface structure
); 


typedef int  (*VCPU_GetIntfFn )( VCPU_ExInterface *intf );        




// SPARC V9 registers access
// regnum = 0-7 (globals)
// wp = 0 (normal) , 1 (alternate) , 2 (mmu), 3 (interrupt)
// regnum = 8-31
// wp = -1 (current), wp >= 0 (window number)

enum {
  VCPU_ACC_CUR = -1, 
  VCPU_ACC_RG  = 0,
  VCPU_ACC_AG  = 1, 
  VCPU_ACC_VG  = 3,
  VCPU_ACC_MG = 2
};



enum {
  VCPU_PR_TPC        = 0x0, 
  VCPU_PR_TNPC       = 0x1,
  VCPU_PR_TSTATE     = 0x2,
  VCPU_PR_TT         = 0x3,
  VCPU_PR_TICK       = 0x4,
  VCPU_PR_TBA        = 0x5,
  VCPU_PR_PSTATE     = 0x6,
  VCPU_PR_TL         = 0x7,
  VCPU_PR_PIL        = 0x8,
  VCPU_PR_CWP        = 0x9,
  VCPU_PR_CANSAVE    = 0xa,
  VCPU_PR_CANRESTORE = 0xb,
  VCPU_PR_CLEANWIN   = 0xc,
  VCPU_PR_OTHERWIN   = 0xd,
  VCPU_PR_WSTATE     = 0xe,
  VCPU_PR_FPQ        = 0xf,
  VCPU_PR_VER        = 0x1f
};


enum {
  VCPU_ASR_Y             = 0,
  VCPU_ASR_CCR           = 2, 
  VCPU_ASR_ASI           = 3,
  VCPU_ASR_TICK          = 4,
  VCPU_ASR_PC            = 5,
  VCPU_ASR_FPRS          = 6,
  VCPU_ASR_MEMBAR        = 15,
  VCPU_ASR_SIGM          = 15,

  VCPU_ASR_PCR           = 16,
  VCPU_ASR_PIC           = 17,
  VCPU_ASR_IEU_CNTRL     = 18,
  VCPU_ASR_GSR           = 19,
  VCPU_ASR_INTR_SET      = 20,
  VCPU_ASR_INTR_CLR      = 21,
  VCPU_ASR_INTR_WRITE    = 22,
  VCPU_ASR_TICK_CMPR     = 23,
  VCPU_ASR_STICK_REG     = 24,
  VCPU_ASR_STICK_CMPR    = 25,
  VCPU_ASR_STICK_THR_STS = 26,  

  // additional regs
  VCPU_ASR_NPC           = 32, 
  VCPU_ASR_FSR           = 33, 

  VCPU_ASR_MAX           = VCPU_ASR_FSR
};

enum {
  VCPU_HPR_HPSTATE       = 0,
  VCPU_HPR_HTSTATE,
  VCPU_HPR_HINTP,
  VCPU_HPR_HTBA,
  VCPU_HPR_HVER,
  VCPU_HPR_HSTICK_CMPR
};





// breakpoint type  
typedef enum
{ 
    VCPU_BP_INSTR_ADDR = 0,
    VCPU_BP_DATA_READ_ADDR,
    VCPU_BP_DATA_WRITE_ADDR,
    VCPU_BP_OPCODE,  
    VCPU_N_BP_TYPES
}
VCPU_BpType; 
 



/////////////////////////////////////////////////////////////
//
// Vcpu hides the details of the cpu specific implementation.
// It presents an abstract interface to the "virtual cpu" -
// for cpu with multiple strands it represents each strands; 
// for cpu without strands it represent the cpu. 

typedef int  (*VCPU_BpActionFn)( int bp_id, int vcpu_id );

class Vcpu
{
 public: 

    VCPU_Config  config;
    VCPU_ImpIntf sys_intf;
    
    
    // priority queue for scheduling future device-sim callbacks 
	EventQue   *eventque;

 public: 

    // virtual interface methods, 
    // when applicable return 0- success, >0- fail; 

    // get/set id
    virtual int set_id(int id)=0; 
    virtual int get_id()=0; 

    // step n number of instructions;
    // each Vcpu can be called from a separate working thread of 
    // the host machine; 
    // Vcpu that belongs to the same core may need to be on the 
    // same working thread to reduce locking for mt safe calls 
    virtual int stepi ( int64_t n=1 )=0; 
    
    // in execution driven mode, stepi only increments tick and calls vtracer::cycle
    // the execdriven_stepi() method is actually called by the exec-driven timing model
    // to advance SAM one instruction at a time
    virtual int execdriven_stepi() { return 0; } // does not have to be supported by implementation

    // signal an interrupt
    virtual int interrupt ( VCPU_InterruptRequest *signal )=0;
    

    // debugger/frontend methods

    // read registers
    virtual int get_ireg (int wp, int regnum, uint64_t & regvalue)=0; 
    virtual int get_freg (int issingle, int regnum, uint64_t & regvalue)=0;

    
    /* the get_pr, get_hpr, get_asr, get_trapreg calls returns 1 if the register is unimplemented */

    // for trap-level specific registers, get/set_pr functions use the current trap_level
    virtual int get_pr(int regnum, uint64_t & value);
    virtual int get_hpr(int regnum, uint64_t & value);
    virtual int get_asr(int regnum, uint64_t & value) = 0;
    virtual int get_trapreg(int tl, int regnum, uint64_t & value) = 0;

    // write registers
    virtual int set_ireg (int wp, int regnum, uint64_t value)=0;
    virtual int set_freg (int issingle, int regnum, uint64_t value)=0;


    // for trap-level specific registers, get/set_pr functions use the current trap_level
    virtual int set_pr(int regnum, uint64_t value) = 0;
    virtual int set_hpr(int regnum, uint64_t value) = 0;
    virtual int set_asr(int regnum, uint64_t value) = 0;
    virtual int set_trapreg(int tl, int regnum, uint64_t value) = 0;
    
    // asi mapped regs
    virtual int get_asi(uint8_t asi, uint64_t addr, uint64_t &data) = 0; 
    virtual int set_asi(uint8_t asi, uint64_t addr, uint64_t  data) = 0;

    // caller must explicitly FREE return_array before it is overwritten or goes out of scope
    virtual int get_tlb_entries(struct TLBInfo * &return_array) = 0;
    
    // mem read - used if caches or write buffer is present;
    // address could be virtuall or physical; 
    // little or big endian access is defined by current state; 
    virtual int read_mem 
    ( 
       uint64_t addr,    // byte address
       uint64_t *value,  // value to load 
       int size,         // number of bytes
       int asi= 0x82,    // ASI_PRIMARY_NO_FAULT
       int is_physical=0 // 1-physical address, 0-virtual address
    )=0;
   

    // mem write 
    virtual int write_mem 
    ( 
       uint64_t addr,  // byte address
       uint64_t value, // value to write 
       int size,       // number of bytes
       int asi=0x82,   // ASI_PRIMARY_NO_FAULT
       int is_physical=0   // 1-physical address, 0-virtual address
    )=0;
    

    
       

    
    // set breakpoint; 
    // when breakpoint hits - instruction should not be commited
    virtual int set_breakpoint 
    ( 
	 int *bp_id,       // return breakpoint id;  
	 VCPU_BpType type,      // breakpoint type
	 uint64_t value,   // opcode, instruction or data address
	 VCPU_BpActionFn action,// call this function on breakpoint hit
	 uint64_t mask= ~(uint64_t(0)) // optional data or addr mask      
    ); 
     

    // remove breakpoint bp_id 
    // if bp_id is ~(0) - remove all instruction bp
    virtual int delete_breakpoint ( int bp_id = ~(0) );
     

    // print breakpoint list to a file/consol
    virtual int print_breakpoints ( FILE *fp ); 
    
    // print all regs to file/consol
    virtual int print_regs ( FILE *fp );
    
    // print tlbs to file/consol
    virtual int print_tlbs ( FILE *fp );

    // speculative mode methods
    ///virtual int get_opcode_speculative ( uint64_t pc_vaddr, uint32_t &opcode ); 
    //virtual int change_pc_speculative  ( uint64_t pc_vaddr ); 
    //virtual int abort ( Instruction *i );

    // virtual destructor
    //virtual ~Vcpu();  
     

};





#endif   // _CPU_LIB_INTERFACE_H
